package com.a918.controller;

import com.a918.consensus.Block;
import com.a918.consensus.ConsensusAlgorithmOperation;
import com.a918.consensus.Node;
import com.a918.dao.BlockInfoMapper;
import com.a918.dao.ConsensusParamMapper;
import com.a918.dao.ConsensusStatisticMapper;
import com.a918.dao.NodeInfoMapper;
import com.a918.dto.TableResponse;
import com.a918.entity.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class ConsensusController {

    private ConsensusParamMapper consensusParamMapper;

    private BlockInfoMapper blockInfoMapper;

    private ConsensusStatisticMapper consensusStatisticMapper;

    private NodeInfoMapper nodeInfoMapper;

    @Autowired
    public ConsensusController(ConsensusParamMapper consensusParamMapper,BlockInfoMapper blockInfoMapper,ConsensusStatisticMapper consensusStatisticMapper,NodeInfoMapper nodeInfoMapper) {
        this.consensusParamMapper = consensusParamMapper;
        this.blockInfoMapper = blockInfoMapper;
        this.consensusStatisticMapper = consensusStatisticMapper;
        this.nodeInfoMapper = nodeInfoMapper;
    }

    @GetMapping("/consensus_algorithm/{type}")
    public String consensusAlgorithm(@PathVariable(value="type",required=true)String type,Model model,HttpServletRequest request) {
        switch(type){
            //共识算法配置
            case "set":
                return "consensus/setting";
            //节点状态数据
            case "search":
                ConsensusStatistic consensusStatistic = consensusStatisticMapper.selectById(1);

                Map<String, Object> map = new HashMap<String, Object>();
                map.put("statistic", consensusStatistic);
                model.addAttribute("statistic",consensusStatistic);
                return "consensus/datacenter";
            default:
                return null;
        }
    }

    @GetMapping("/consensus_visualization/{type}")
    public String consensusVisualization(@PathVariable(value="type",required=true)String type, Model model) {
        switch(type){
            //
            case "verify":
                return "consensus/analyse";
            //
            case "throughput":
                return "consensus/analyse";
            //
            case "badnode":
                return "consensus/analyse";
            //
            case "decentralized":
                return "consensus/analyse";
            default:
                return null;
        }
    }

    //参数设置列表
    @RequestMapping(value = "/get_consensus_param")
    @ResponseBody
    public Object getConsensusParam(@RequestParam Map<String, String> paramMap) {

        int pno=Integer.parseInt(paramMap.get("page"));
        int pageSize=Integer.parseInt(paramMap.get("limit"));
        PageHelper.startPage(pno, pageSize);

        List<ConsensusParam> list=consensusParamMapper.selectList(null);

        PageInfo<ConsensusParam> pageInfo_param= new PageInfo<ConsensusParam>(list);

        return new TableResponse(0,"查询成功", pageInfo_param.getList(),pageInfo_param.getTotal());
    }

    //查询单一参数
    @RequestMapping(value = "/get_one_consensus_param")
    @ResponseBody
    public Map<String, Object> getOneConsensusParam(HttpServletRequest request, Model model){
        Integer id = Integer.valueOf(request.getParameter("id"));// 获取参数

        ConsensusParam consensusParam = consensusParamMapper.selectById(id);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("param", consensusParam);
        model.addAttribute("param",consensusParam);
        return map;

    }

    @PostMapping(value = "/update_alg")
    @ResponseBody
    public String updateAlg(@RequestParam("alg") String alg, HttpSession session, Model model){
        System.out.println("alg:"+alg);
        if (Integer.parseInt(alg) == 0) {
            session.setAttribute("alg","DPOSPT共识算法");
        } else  if (Integer.parseInt(alg) == 1) {
            session.setAttribute("alg","基于信誉度的共识算法");
        } else if (Integer.parseInt(alg) == 2) {
            session.setAttribute("alg","融合共识算法");
        } else {
            return "error";
        }
        return "success";
    }

    @PostMapping(value = "/update_consensus_param")
    @ResponseBody
    public String updateConsensusParam(@RequestBody ConsensusParam consensusParam, Model model){
        try {
            consensusParamMapper.updateById(consensusParam);
            return "success";
        } catch (Exception e) {
            return "error";
        }
    }

    //查询区块信息
    @RequestMapping(value = "/get_block_info")
    @ResponseBody
    public Object getBlockInfo(@RequestParam Map<String, String> paramMap) {
        int pno=Integer.parseInt(paramMap.get("page"));
        int pageSize=Integer.parseInt(paramMap.get("limit"));
        PageHelper.startPage(pno, pageSize);

        List<BlockInfo> list=blockInfoMapper.selectList(null);


        if (list.size()>0) {
            PageInfo<BlockInfo> pageInfo_param= new PageInfo<BlockInfo>(list);

            return new TableResponse(0,"查询成功", pageInfo_param.getList(),pageInfo_param.getTotal());

        }else {
            return new TableResponse(0,"查询成功", new ArrayList<>(),0);
        }

    }


    //查询单一参数
    @RequestMapping(value = "/get_consensus_statistic")
    public String getConsensusStatistic(HttpServletRequest request, Model model){

        ConsensusStatistic consensusStatistic = consensusStatisticMapper.selectById(1);

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("statistic", consensusStatistic);
        model.addAttribute("statistic",consensusStatistic);
        //request.getSession().setAttribute("statistic",consensusStatistic);
        return "consensus/datacenter";
    }


    @RequestMapping(value = "/getProgress")
    @ResponseBody
    public Object GetProgress( HttpServletRequest request) {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e){
            System.out.println(e);
        }
        return "success";
    }

    //获取区块信息
    @RequestMapping(value = "/update_block_info")
    @ResponseBody
    public String updateBlockInfo() {
        // 删除之前的区块信息
        List<BlockInfo> currentBlockInfo =blockInfoMapper.selectList(null);
        for (BlockInfo blockInfo : currentBlockInfo) {
            blockInfoMapper.deleteById(blockInfo.getId());
        }
        // 删除之前的节点信息
        List<NodeInfo> currentNodeInfo =nodeInfoMapper.selectList(null);
        for (NodeInfo nodeInfo : currentNodeInfo) {
            nodeInfoMapper.deleteById(nodeInfo.getId());
        }

        // 获取之前的区块链共识统计信息 这个表只存一条
        ConsensusStatistic consensusStatistic = consensusStatisticMapper.selectById(1);

        int n = 50;
        String type = "DPOSPT";
        double initialTimeout = 0.1;
        double TIME_LIMIT=4;
        int correctNodeCount= consensusParamMapper.selectById(4).getValue().intValue();
        int failedNodeCout=consensusParamMapper.selectById(8).getValue().intValue();
        double token=consensusParamMapper.selectById(5).getValue();
        double credit=consensusParamMapper.selectById(6).getValue();
        int round=consensusParamMapper.selectById(3).getValue().intValue();
        int delegateNum=consensusParamMapper.selectById(7).getValue().intValue();
        double reward=consensusParamMapper.selectById(1).getValue();
        double beta=consensusParamMapper.selectById(2).getValue();

        // 运行 》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
        System.out.println("start");
        Map<String,Object> result = ConsensusAlgorithmOperation.getDPOSPTBlockInfo(n,type,initialTimeout,correctNodeCount,failedNodeCout,token,credit,round,delegateNum,TIME_LIMIT,reward,beta);
        System.out.println("end");

        consensusStatistic.setFailRate((Double) result.get("FailRate"));
        consensusStatistic.setGiniIndex((Double) result.get("GiniIndex"));
        consensusStatistic.setAvgTime((Double) result.get("AvgTime"));

        List<Node> nodes = (List<Node>)result.get("nodeInfo");
        System.out.println(nodes);
        consensusStatistic.setTotalNodeNum(nodes.size());

        Map<Integer,Map<String,Object>> blockInfoMap = (Map<Integer, Map<String, Object>>) result.get("blockInfo");
        List<BlockInfo> list = new ArrayList<>();
        Integer block_num = 0;
        Integer success_node_num = 0;
        Integer fail_node_num = 0;
        Integer delegate_num = 0;


        for (int r = 1;r <= round;r++) {
            Map<String,Object> voteInfo = blockInfoMap.get(r);
            List<Node> selectedDelegates = (List<Node>) voteInfo.get("selectedDelegates");
            delegate_num = selectedDelegates.size();
            for (Node selectedDelegate : selectedDelegates) {
                // 存入数据库
                NodeInfo nodeInfo = new NodeInfo(selectedDelegate.toString().substring(19),selectedDelegate.getToken(),selectedDelegate.getCredit(),-1,r);
                nodeInfoMapper.insert(nodeInfo);
            }

            List<Map<String,Object>> vlist = (List<Map<String, Object>>) voteInfo.get("blockInfo");

            for (Map<String, Object> map : vlist) {
                BlockInfo blockInfo = new BlockInfo();
                Block block = (Block) map.get("区块");
                Node creator = (Node) map.get("生产节点");
                Node failNode = (Node) map.get("作恶节点");

                if (failNode==null) {
                    // 出块成功
                    blockInfo.setBlockIndex(block.getIndex());
                    blockInfo.setPreviousHash(block.getPreviousHash());
                    blockInfo.setTimestamp(block.getTimestamp());
                    blockInfo.setNodeIndex(creator.toString().substring(19));
                    blockInfo.setToken(creator.getToken());
                    blockInfo.setCredit(creator.getCredit());
                    blockInfo.setStatus(1);

                    // 信息
                    block_num = block.getIndex();// 递增更新
                    success_node_num +=1;

                    // 存入数据库
                    NodeInfo nodeInfo = new NodeInfo(creator.toString().substring(19),creator.getToken(),creator.getCredit(),1,0);
                    nodeInfoMapper.insert(nodeInfo);

                } else {
                    // 节点作恶
                    blockInfo.setNodeIndex(failNode.toString().substring(19));
                    blockInfo.setToken(failNode.getToken());
                    blockInfo.setCredit(failNode.getCredit());
                    blockInfo.setStatus(0);
                    fail_node_num+=1;

                    // 存入数据库
                    NodeInfo nodeInfo = new NodeInfo(failNode.toString().substring(19),failNode.getToken(),failNode.getCredit(),0,0);
                    nodeInfoMapper.insert(nodeInfo);
                }
                list.add(blockInfo);
                blockInfoMapper.insert(blockInfo);

            }
        }
        consensusStatistic.setBlockNum(block_num+1);// 因为从0开始
        consensusStatistic.setSuccessNodeNum(success_node_num);
        consensusStatistic.setFailNodeNum(fail_node_num);
        consensusStatistic.setDelegateNum(delegate_num);
        consensusStatisticMapper.updateById(consensusStatistic);

        return "success";
    }


    //查询节点列表

    @GetMapping(value = "/get_node_list")
    public String getNodeList(HttpServletRequest request, Model model) {
        Integer status = Integer.valueOf(request.getParameter("status"));// 获取参数, 1: 正常节点，0：作恶节点，-1：见证人节点

        QueryWrapper<NodeInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status",status);
        if (status != -1) {
            queryWrapper.eq("round",0);
        } else {
            queryWrapper.ne("round",0);
        }
        List<NodeInfo> list = nodeInfoMapper.selectList(queryWrapper);
        model.addAttribute("list",list);
        model.addAttribute("status",status);
        return "consensus/node_list";

    }

}
